package com.alpha.eceasy.auth;

import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.alpha.eceasy.core.R;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;

@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Resource
    private AuthenticationManager authenticationManager;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 1、从请求头中获取token，如果请求头中不存在token，直接放行即可！由Spring Security的过滤器进行校验！
        String token = request.getHeader("Authorization");
        if (token == null || token.isEmpty()) {
            filterChain.doFilter(request, response);
            return;
        }
        log.info("JwtAuthenticationTokenFilter.token = {}", token);
        // 2、对token进行解析，验证有效性
        try {
            JWTUtil.verify(token.substring(7), JWTSignerUtil.none());
        } catch (Exception e) {
//            filterChain.doFilter(request, response);
            response.setContentType("application/json;charset=utf-8");
            HashMap<String, Object> map = new HashMap<>();
            map.put("code", 401);
            map.put("msg", "非法token");
            map.put("data", "非法token");
            JSONUtil.toJsonStr(map, response.getWriter());
            return;
        }

        // 3、使用userId从redis中查询对应的LoginUser对象
        JWT jwt = JWTUtil.parseToken(token.substring(7));

        // 4、然后将查询到的LoginUser对象的相关信息封装到UsernamePasswordAuthenticationToken对象中，然后将该对象存储到Security的上下文对象中
        UserLoginTypeEnum userLoginType = UserLoginTypeEnum.valueOf((String) jwt.getPayload("userLoginType"));
        AbstractAuthenticationToken authenticationToken = switch (userLoginType) {
            case ACCOUNT_AND_PASSWORD ->
                    new UsernamePasswordAuthenticationToken(jwt.getPayload("principal"), jwt.getPayload("credentials"));
            case PHONE_AND_CODE -> null;
            case OPEN_TOKEN -> new AnonymousAuthenticationToken("OPEN_TOKEN", jwt.getPayload("openToken"),
                    Collections.singletonList(new SimpleGrantedAuthority("ROLE_INNER")));
        };
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        SecurityContextHolder.getContext().setAuthentication(authenticate);

        // 5.放行
        filterChain.doFilter(request, response);
    }
}